/**
 * @file XListView.java
 * @create Mar 18, 2012 6:28:41 PM
 * @modify Jul 18, 2016 3:06:26 PM
 * @author Maxwin
 * @modifier luzx
 * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more.
 * 		Implement IXListViewListener, and see stopRefresh() / stopLoadMore().
 */
package com.fablesoft.projectdatacollect.view;

import com.fablesoft.projectdatacollect.R;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.DecelerateInterpolator;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.Scroller;
import android.widget.TextView;

public class MyRefreshListView extends ListView implements OnScrollListener {

	private float mLastY = -1; // save event y
	private Scroller mScroller; // used for scroll back
	private OnScrollListener mScrollListener; // user's scroll listener
	// the interface to trigger refresh and load more.
	private RefreshListViewListener mListViewListener;
	// -- header view
	private MyRefreshHeader mHeaderView;
	// header view content, use it to calculate the Header's height. And hide it
	// when disable pull refresh.
	private RelativeLayout mHeaderViewContent;
//	private TextView mHeaderTimeView;
	private View footerProgressbar;
	private TextView footerHintText;
	private View footerLoadingView;
	private int mHeaderViewHeight; // header view's height
	private boolean mEnablePullRefresh = true;
	private boolean mPullRefreshing = false; // is refreashing.
	// -- footer view
	private View mFooterView;
	private boolean mEnablePullLoad = true;
	private boolean mPullLoading;
	private boolean mIsFooterReady = false;
	private boolean isBottom;// 是否最底部
	private final static float RADIO = 100;
	private final static int SCROLL_DURATION = 120; // scroll back duration
	private final static float OFFSET_RADIO = 1.8f; // support iOS like pull
	private Animation loadAnimation;
	/**
	 * @param context
	 */
	public MyRefreshListView(Context context) {
		super(context);
		initWithContext(context);
	}

	public MyRefreshListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		initWithContext(context);
	}

	public MyRefreshListView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		initWithContext(context);
	}

	private void initWithContext(Context context) {
		mScroller = new Scroller(context, new DecelerateInterpolator());
		super.setOnScrollListener(this);

		// init header view
		mHeaderView = new MyRefreshHeader(context);
		mHeaderViewContent = (RelativeLayout) mHeaderView
				.findViewById(R.id.listview_header_content);
//		mHeaderTimeView = (TextView) mHeaderView
//				.findViewById(R.id.xlistview_header_time);
		addHeaderView(mHeaderView);

		// init footer view
		mFooterView = LayoutInflater.from(context).inflate(
				R.layout.listview_load_footer, null);
		footerProgressbar = mFooterView
				.findViewById(R.id.listview_footer_progressbar);
		footerHintText = (TextView) mFooterView
				.findViewById(R.id.listview_footer_hint_textview);
		footerLoadingView = mFooterView
				.findViewById(R.id.listview_footer_loading_content);
		mFooterView.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				startLoadMore();
			}
		});
		// init header height
		mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(
				new OnGlobalLayoutListener() {
					@Override
					public void onGlobalLayout() {
						mHeaderViewHeight = mHeaderViewContent.getHeight();
						getViewTreeObserver()
								.removeGlobalOnLayoutListener(this);
					}
				});
	}

	@Override
	public void setAdapter(ListAdapter adapter) {
		// make sure XListViewFooter is the last footer view, and only add once.
		if (mIsFooterReady == false) {
			mIsFooterReady = true;
			addFooterView(mFooterView);
		}
		super.setAdapter(adapter);
	}

	/**
	 * enable or disable pull down refresh feature.
	 * 
	 * @param enable
	 */
	public void setPullRefreshEnable(boolean enable) {
		mEnablePullRefresh = enable;
		if (!mEnablePullRefresh) { // disable, hide the content
			mHeaderViewContent.setVisibility(View.GONE);
		} else {
			mHeaderViewContent.setVisibility(View.VISIBLE);
		}
	}

	/**
	 * enable or disable pull up load more feature.
	 * 
	 * @param enable
	 */
	public void setPullLoadEnable(boolean enable) {
		mEnablePullLoad = enable;
		if (!mEnablePullLoad) {
			Log.i("lzx", "removeFooterView");
//			mFooterView.setVisibility(View.GONE);
			removeFooterView(mFooterView);
		} else {
//			mPullLoading = false;
//			mFooterView.setVisibility(View.VISIBLE);
			removeFooterView(mFooterView);
			addFooterView(mFooterView);
		}
	}

	/**
	 * stop refresh, reset header view.
	 */
	public void stopRefresh() {
		if (mPullRefreshing == true) {
			mPullRefreshing = false;
			resetHeaderHeight();
			mHeaderView.setState(MyRefreshHeader.STATE_NORMAL);
		}
	}

	public void setNoDataLoad() {
		mEnablePullLoad = false;
		mPullLoading = false;
		footerProgressbar.clearAnimation();
		footerLoadingView.setVisibility(View.INVISIBLE);
		footerHintText.setVisibility(View.VISIBLE);
		footerHintText.setText(R.string.load_no_data);
	}
	
	/**
	 * stop load more, reset footer view.
	 */
	public void stopLoadMore() {
		if (mPullLoading == true && mEnablePullLoad) {
			mPullLoading = false;
			footerProgressbar.clearAnimation();
			footerLoadingView.setVisibility(View.INVISIBLE);
			footerHintText.setVisibility(View.VISIBLE);
			footerHintText.setText(R.string.listview_footer_hint_normal);
		}
	}
	
	private void updateHeaderHeight(float delta) {
//		if(delta > 0){
//			if(mHeaderView.getVisiableHeight() <= mHeaderViewHeight){
//				mHeaderView.setVisiableHeight((int) delta
//						+ mHeaderView.getVisiableHeight());
//			}
//		}else{
//			mHeaderView.setVisiableHeight((int) delta
//					+ mHeaderView.getVisiableHeight());
//		}
		mHeaderView.setVisiableHeight((int) delta
				+ mHeaderView.getVisiableHeight());
		if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态
			if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
				mHeaderView.setState(MyRefreshHeader.STATE_READY);
			} else {
				mHeaderView.setState(MyRefreshHeader.STATE_NORMAL);
			}
		}
//		setSelection(0); // scroll to top each time
	}

	/**
	 * reset header view's height.
	 */
	private void resetHeaderHeight() {
		int height = mHeaderView.getVisiableHeight();
		if (height == 0) // not visible.
			return;
		// refreshing and header isn't shown fully. do nothing.
		if (mPullRefreshing && height <= mHeaderViewHeight) {
			return;
		}
		int finalHeight = 0; // default: scroll back to dismiss header.
		// is refreshing, just scroll back to show all the header.
		if (mPullRefreshing && height > mHeaderViewHeight) {
			finalHeight = mHeaderViewHeight;
		}
		mScroller.startScroll(0, height, 0, finalHeight - height,
				SCROLL_DURATION);
		// trigger computeScroll
		invalidate();
	}

//	@Override
//	public void onWindowFocusChanged(boolean hasWindowFocus) {
//		super.onWindowFocusChanged(hasWindowFocus);
//		Log.i("lzx", "onWindowFocusChanged:" + mHeaderView.getVisiableHeight());
//		if(mHeaderView.getVisiableHeight() > 0){
//			resetHeaderHeight();
//		}
//	}
	
	private void startLoadMore() {
		if(!mEnablePullLoad){
			return;
		}
		mPullLoading = true;
		if(loadAnimation == null){
			loadAnimation = AnimationUtils.loadAnimation(getContext() ,R.anim.loading);
		}
		footerLoadingView.setVisibility(View.VISIBLE);
		footerHintText.setVisibility(View.GONE);
		footerProgressbar.startAnimation(loadAnimation);
		if (mListViewListener != null) {
			mListViewListener.onLoadMore();
		}
	}

	/**
	 * Actions a Pull Event
	 * 
	 * @return true if the Event has been handled, false if there has been no
	 *         change
	 */
	private void pullEvent() {
		final int newScrollValue;
		newScrollValue = mHeaderView.getHeight();
		if (newScrollValue != 0) {
			float scale = Math.abs(newScrollValue) / RADIO;
			mHeaderView.onPullImpl(scale);
		}
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent ev) {
		if (mLastY == -1) {
			mLastY = ev.getRawY();
		}
		switch (ev.getAction()) {
		case MotionEvent.ACTION_DOWN:
//			Log.i("lzx", "ACTION_DOWN");
			mLastY = ev.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
//			Log.i("lzx", "ACTION_MOVE");
			final float deltaY = ev.getRawY() - mLastY;
			mLastY = ev.getRawY();
			if (mEnablePullRefresh && getFirstVisiblePosition() == 0
					&& (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) {
				// the first item is showing, header has shown or pull down.
				updateHeaderHeight(deltaY / OFFSET_RADIO);
				pullEvent();
			}
			break;
		case MotionEvent.ACTION_UP:
//			Log.i("lzx", "ACTION_UP");
			mLastY = -1; // reset
			if (getFirstVisiblePosition() == 0) {
				// invoke refresh
				if (mEnablePullRefresh
						&& mHeaderView.getVisiableHeight() > mHeaderViewHeight) {
					mHeaderView.setState(MyRefreshHeader.STATE_REFRESHING);
					if (mListViewListener != null && !mPullRefreshing) {
						mListViewListener.onRefresh();
						mPullRefreshing = true;
					}
				}
				resetHeaderHeight();
			}
			if(mScroller.computeScrollOffset()){
				mHandler.removeMessages(0);
				mHandler.sendEmptyMessageDelayed(0, SCROLL_DURATION);
			}else{
				mHandler.removeMessages(0);
				mHandler.sendEmptyMessage(0);
			}
			if (isBottom && !mPullLoading && mEnablePullLoad && !mPullRefreshing && ViewCompat.canScrollVertically(this, -1)) {
				// invoke load more.
				startLoadMore();
			}
			break;
		}
		return super.onTouchEvent(ev);
	}

	Handler mHandler = new Handler(){
		@Override
		public void handleMessage(Message msg) {
			if(mPullRefreshing){
//				Log.i("lzx", "FirstVisiblePosition:" + (getChildAt(getFirstVisiblePosition()) != mHeaderView));
					Log.i("lzx", "set mHeaderViewHeight max ");
					mHeaderView.setVisiableHeight(mHeaderViewHeight);
			}else{
				Log.i("lzx", "set mHeaderViewHeight min");
				mHeaderView.setVisiableHeight(0);
			}
			if(getChildAt(getFirstVisiblePosition()) == mHeaderView){
				setSelection(0);
			}
		};
	};
	
	@Override
	public void computeScroll() {
		if (mScroller.computeScrollOffset()) {
			mHeaderView.setVisiableHeight(mScroller.getCurrY());
			postInvalidate();
		}else{
//			Log.i("lzx", "mHeaderView.getVisiableHeight():" + mHeaderView.getVisiableHeight());
//			if(mPullRefreshing){
//				if(mHeaderView.getVisiableHeight() > 120){
//					mHeaderView.setVisiableHeight(mHeaderViewHeight);
//				}
//			}
		}
		super.computeScroll();
	}

	@Override
	public void setOnScrollListener(OnScrollListener l) {
		mScrollListener = l;
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		if (scrollState == OnScrollListener.SCROLL_STATE_IDLE && !mPullLoading
				&& mEnablePullLoad && ViewCompat.canScrollVertically(this, -1)) {
			if (isBottom) {
				startLoadMore();
			}
		}
		if (mScrollListener != null) {
			mScrollListener.onScrollStateChanged(view, scrollState);
		}
	}

	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		int lastItem = firstVisibleItem + visibleItemCount;
		if (lastItem == totalItemCount) {
			isBottom = true;
		} else {
			isBottom = false;
		}	
		if (mScrollListener != null) {
			mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
					totalItemCount);
		}
	}

	public void setRefreshListViewListener(RefreshListViewListener l) {
		mListViewListener = l;
	}

	/**
	 * implements this interface to get refresh/load more event.
	 */
	public interface RefreshListViewListener {
		public void onRefresh();

		public void onLoadMore();
	}
}
